package com.arui.rpc.transport;

import com.arui.rpc.entity.RpcRequest;
import com.arui.rpc.entity.RpcResponse;
import com.arui.rpc.transport.netty.client.NettyClient;
import com.arui.rpc.transport.socket.client.SocketClient;
import com.arui.rpc.util.RpcMessageChecker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

/**
 * @Auther: zhanyurui
 * @Date: 2021-08-08 18:25
 * @Description: RPC客户端动态代理
 */
public class RpcClientProxy implements InvocationHandler {


    private static final Logger logger = LoggerFactory.getLogger(RpcClientProxy.class);
    private final RpcClient client;

    public RpcClientProxy(RpcClient client) {
        this.client = client;
    }

    @SuppressWarnings("unchecked")
    public <T> T getProxy(Class<T> clazz){
        return (T)Proxy.newProxyInstance(clazz.getClassLoader(),new Class<?>[]{clazz},this);
    }
    @SuppressWarnings("unchecked")
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        logger.info("调用方法: {}#{}", method.getDeclaringClass().getName(), method.getName());

        RpcRequest rpcRequest = RpcRequest.builder()
                .requestId(UUID.randomUUID().toString())
                .interfaceName(method.getDeclaringClass().getName())
                .methodName(method.getName())
                .parameters(args)
                .paramTypes(method.getParameterTypes())
                .heartBeat(false)
                .build();

        RpcResponse rpcResponse = null;
       if (client instanceof NettyClient){
           try {
               CompletableFuture<RpcResponse> completableFuture = (CompletableFuture<RpcResponse>)client.sendRequest(rpcRequest);
               rpcResponse = completableFuture.get();
           }catch (Exception e){
               logger.error("方法调用请求发送失败", e);
               return null;
           }

       }
        if (client instanceof SocketClient) {
             rpcResponse = (RpcResponse) client.sendRequest(rpcRequest);
        }
        RpcMessageChecker.check(rpcRequest, rpcResponse);
        return rpcResponse.getData();
    }
}
